import { Note, SERVER_URL } from './const';

// 自定义事件，标识note被更新
const NOTE_STORAGE_CHANGE = new Event('note-storage-change');
// 自定义事件，标识网络状况
const NET_ERROR = new Event('net-error');
const NET_SUCCESS = new Event('net-success');

// 封装localstorage存值方法，自动派发事件
const setItem = (key: string, value: any) => {
  localStorage.setItem(key, JSON.stringify(value));
  window.dispatchEvent(NOTE_STORAGE_CHANGE);
};

export const getCurrentDatabaseVersion = () => {
  return JSON.parse(localStorage.getItem('note-version') || '0');
};

// 重新设置数据的version
export const freshDatabaseVersion = (version?: string) => {
  if (!version) {
    let tempVersion = new Date().getTime();
    // 保证时间戳不会重复
    while (tempVersion === parseInt(getCurrentDatabaseVersion())) {
      tempVersion += 1;
    }
    version = String(tempVersion);
  }
  setItem('note-version', version);
};

export const saveNoteList = (noteList: Note[], version?: string) => {
  setItem('note-list', noteList);
  freshDatabaseVersion(version);
};

export const getNoteList = () => {
  const noteJson = localStorage.getItem('note-list');
  return noteJson ? JSON.parse(noteJson) : [];
};

export const saveNote = (note: Note, index: number) => {
  const copyNoteList = getNoteList();
  copyNoteList[index] = note;
  saveNoteList(copyNoteList);
};

export const addNote = (note: Note) => {
  const copyNoteList = getNoteList();
  copyNoteList.push(note);
  saveNoteList(copyNoteList);
};

export const getNote = (index: number) => {
  const copyNoteList = getNoteList();
  return copyNoteList[index];
};

export const delNote = (index: number) => {
  const copyNoteList = getNoteList();
  copyNoteList.splice(index, 1);
  saveNoteList(copyNoteList);
};

// 与后端同步

// 获取后端的数据版本号
export const getCloudDatabaseVersion = async () => {
  try {
    const res = await (
      await fetch(`${SERVER_URL}api/version/`, { mode: 'cors' })
    ).json();

    window.dispatchEvent(NET_SUCCESS);

    return res?.version;
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
    return 0;
  }
};

export const updateNoteDatabase = async (version?: string) => {
  if (!version) {
    version = await getCloudDatabaseVersion();
  }

  try {
    const cloudNoteList = await (
      await fetch(`${SERVER_URL}api/notelist/`, { mode: 'cors' })
    ).json();

    window.dispatchEvent(NET_SUCCESS);

    saveNoteList(
      cloudNoteList?.data.filter((item: any) => !!item) || [],
      version,
    );
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
  }

  return;
};

export const checkUpdate = async () => {
  const cloudVersion = await getCloudDatabaseVersion();
  const localVersion = getCurrentDatabaseVersion();

  // 如果后端版本号高于本地，则拉取更新
  // 否者向服务器发送最新列表
  if (parseInt(cloudVersion) > parseInt(localVersion)) {
    await updateNoteDatabase(cloudVersion);
  } else if (parseInt(cloudVersion) < parseInt(localVersion)) {
    setNotesToCloud(getNoteList());
  }
  return;
};

// 如果网络错误，则将改动放在暂存区，下次再次请求
// 改动类型分为 新增 | 修改
enum CommitType {
  ADD,
  DEL,
  CHANGE,
}

interface Commit {
  type: CommitType;
  note?: Note;
  index?: number;
}

const noteCommitList: Commit[] = JSON.parse(
  localStorage.getItem('note-commit-list') || '[]',
);

// 在网络正常时将改动列表的内容取出来一一重做
const redoCommit = () => {
  while (noteCommitList.length > 0) {
    const commit = noteCommitList.pop();
    if (commit) {
      const { type, note, index } = commit;
      if (type === CommitType.ADD && note) {
        addNoteToCloud(note);
      } else if (type === CommitType.CHANGE && note) {
        setNoteToCloud(note, index || 0);
      } else if (type === CommitType.DEL) {
        delNoteToCloud(index || 0);
      }
    }
  }
};

// 将改动列表持久化，防止页面关闭丢失
const saveCommitList = () => {
  localStorage.setItem('note-commit-list', JSON.stringify(noteCommitList));
};

// 向后端增加note
export const addNoteToCloud = async (note: Note) => {
  try {
    // 先将未成功的改动列表进行重做
    redoCommit();

    await fetch(`${SERVER_URL}api/notes/`, {
      body: JSON.stringify({
        data: note,
        version: getCurrentDatabaseVersion(),
      }),
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      mode: 'cors',
    });

    window.dispatchEvent(NET_SUCCESS);
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
    noteCommitList.push({
      type: CommitType.ADD,
      note,
    });
  }

  saveCommitList();

  return;
};

// 向后端更新note
export const setNoteToCloud = async (note: Note, index: number) => {
  try {
    // 先将未成功的改动列表进行重做
    redoCommit();

    await fetch(`${SERVER_URL}api/notes/${index}`, {
      body: JSON.stringify({
        data: note,
        version: getCurrentDatabaseVersion(),
      }),
      method: 'PUT',
      headers: { 'content-type': 'application/json' },
      mode: 'cors',
    });

    window.dispatchEvent(NET_SUCCESS);
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
    noteCommitList.push({
      type: CommitType.CHANGE,
      note,
      index,
    });
  }

  saveCommitList();

  return;
};

// 向后端删除note
export const delNoteToCloud = async (index: number) => {
  try {
    // 先将未成功的改动列表进行重做
    redoCommit();

    await fetch(`${SERVER_URL}api/notes/${index}`, {
      body: JSON.stringify({
        index,
        version: getCurrentDatabaseVersion(),
      }),
      method: 'DELETE',
      headers: { 'content-type': 'application/json' },
      mode: 'cors',
    });

    window.dispatchEvent(NET_SUCCESS);
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
    noteCommitList.push({
      type: CommitType.DEL,
      index,
    });
  }

  saveCommitList();

  return;
};

// 向后端更新全部note
export const setNotesToCloud = async (notelist: Note[]) => {
  try {
    // 先将未成功的改动列表进行重做
    redoCommit();

    await fetch(`${SERVER_URL}api/notelist/`, {
      body: JSON.stringify({
        data: notelist,
        version: getCurrentDatabaseVersion(),
      }),
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      mode: 'cors',
    });

    window.dispatchEvent(NET_SUCCESS);
  } catch (error) {
    console.log(error);
    window.dispatchEvent(NET_ERROR);
  }

  return;
};

// const DB_NAME = 'NOTE';
// let database: any;
// export const getDB = async () => {
//   if (database) {
//     return database;
//   }

//   return new Promise((resolve, reject) => {
//     const indexedDB = window.indexedDB;

//     const req = indexedDB.open(DB_NAME);

//     req.onsuccess = (res: any) => {
//       database = res.target.result;
//       resolve(database);
//     };

//     req.onerror = (err: any) => {
//       reject(err);
//     };

//     req.onupgradeneeded = () => {
//       if (!database.objectStoreNames.contains(DB_NAME)) {
//         database.createObjectStore(DB_NAME, { keyPath: 'id' });
//       }
//     };
//   });
// };

// export const updateNote = (note: Note) => {
//   return new Promise(async (resolve, reject) => {
//     const db = await getDB();
//     const req = db.transaction([DB_NAME], 'readwrite').objectStore(DB_NAME).put(note);

//     req.onsuccess = () => {
//       resolve();
//     };

//     req.onerror = (err: any) => {
//       reject(err)
//     };
//   });
// };

// export const addNote = (note: Note) => {
//   return new Promise(async (resolve, reject) => {
//     const db = await getDB();
//     const req = db.transaction([DB_NAME], 'readwrite').objectStore(DB_NAME).add(note);

//     req.onsuccess = () => {
//       resolve();
//     };

//     req.onerror = (err: any) => {
//       reject(err)
//     };
//   });
// };

// export const delNote = (key: string) => {
//   return new Promise(async (resolve, reject) => {
//     const db = await getDB();
//     const req = db.transaction([DB_NAME], 'readwrite').objectStore(DB_NAME).delete(key);

//     req.onsuccess = () => {
//       resolve();
//     };

//     req.onerror = (err: any) => {
//       reject(err)
//     };
//   });
// };
